#ifndef _MPP_COMMON_H
#define _MPP_COMMON_H

#include <stdint.h>
#include <stdio.h>
#include <stddef.h>

#define CODEC_ALIGN(x, a)   (((x)+(a)-1)&~((a)-1))

#ifdef __cplusplus
extern "C" {
#endif

#define cxx_log(fmt,...)\
            do {\
                printf(fmt,##__VA_ARGS__);\
            } while(0)




typedef  enum
{
    MPP_RET_CODE_OK,
    MPP_RET_CODE_WAITE,
    MPP_RET_CODE_FAILURE,
}RET_CODE;

typedef  enum
{
    MPP_TYPE_H264,
    MPP_TYPE_H265,
    MPP_TYPE_MJPEG,
    MPP_TYPE_MPEG4,
    MPP_TYPE_FAILURE,

}CODE_TYPE;
typedef enum
{
    MPP_FRAME_TYPE_YUV420SP,     /* YYYY... UV... (NV12)     */
    MPP_FRAME_TYPE_YUV422,       /* YYYY... UVUV... (NV16)   */
    MPP_FRAME_TYPE_YUV420SP_VU,  /* YYYY... VUVUVU... (NV21) */
    MPP_FRAME_TYPE_YUV422SP_VU,  /* YYYY... VUVUVU... (NV61) */
    MPP_FRAME_TYPE_YUV422P,      /* YYYY... UU...VV...(422P) */



    MPP_FRAME_TYPE__RGBA_8888,
    MPP_FRAME_TYPE__RGBX_8888,
    MPP_FRAME_TYPE__RGB_888,
    MPP_FRAME_TYPE__BGRA_8888,
    MPP_FRAME_TYPE__RGB_565,
    MPP_FRAME_TYPE__RGBA_5551,
    MPP_FRAME_TYPE__RGBA_4444,
    MPP_FRAME_TYPE__BGR_888,
    MPP_FRAME_TYPE__BGRX_8888 ,
    MPP_FRAME_TYPE__BGR_565 ,
    MPP_FRAME_TYPE__BGRA_5551,
    MPP_FRAME_TYPE__BGRA_4444,
}FRAME_TYPE;




typedef enum
{
    ENCODE_RC_MODE_VBR,
    ENCODE_RC_MODE_CBR,
    ENCODE_RC_MODE_FIXQP,
    ENCODE_RC_MODE_AVBR
}ENCODE_RC_MODE;

//*****************************************************************
//**********************图像处理相关操作*****************************
//*****************************************************************
typedef enum
{
    IMAGE_ROTAION_HOR = 0x0001,   //--水平翻转 左右镜像
    IMAGE_ROTAION_VER = 0x0002,   //--垂直翻转 上下镜像
    IMAGE_ROTAION_90  = 0x0004,    //--90度翻转
    IMAGE_ROTAION_180 = 0x0008 ,   //--180度翻转
    IMAGE_ROTAION_270 = 0x0010 ,   //--270度翻转
}IMAGE_ROTAION;

typedef struct
{
    int src_x ;
    int src_y;    // --原图需要裁剪的x,y
    int src_clipping_width; //--在原图中需要裁剪的宽度
    int src_clipping_hight; //--在原图中需要裁剪的高度
}IMAGE_CLIPPING_T;


typedef enum
{
    IMAGE_PROCESS_ROTAION       = 0x01,      //--翻转
    IMAGE_PROCESS_CLIPPING      = 0x02,     //--裁剪
    IMAGE_PROCESS_FORMAT_CONVER = 0x04,     //--格式转换
    IMAGE_PROCESS_ZOOM          = 0x08,     //--图像缩放
    IMAGE_PROCESS_OVERLAY       = 0x10,      //--叠加
}IMAGE_PROCESS_FLG;

typedef struct
{
    uint32_t hight;   // -- 高度
    uint32_t width;   // --宽度
}IMAGE_SIZE_T;








typedef struct
{
    uint32_t Img_ProcessFlg;    //--图像处理的FLG 【IMAGE_PROCESS_FLG】 注：会根据这个FLG中的标志位执行某个功能 图像叠加的接口暂时未添加
                                // 注：如需要裁剪+翻转 可以将Img_ProcessFlg = IMAGE_PROCESS_ROTAION|IMAGE_PROCESS_CLIPPING
    IMAGE_SIZE_T srcRecSize;    //--原图尺寸
    IMAGE_SIZE_T dstRecSize;    //--目标尺寸
    FRAME_TYPE   srcFormat;     //--原图格式
    FRAME_TYPE   dstFormat;     //--目标格式

    IMAGE_CLIPPING_T    img_clipping;            //--裁剪
    uint32_t            img_rotaion;             //--翻转【IMAGE_ROTAION】注：需要水平+上下翻转 img_rotaion = IMAGE_ROTAION_HOR|IMAGE_ROTAION_VER
    


}IMAGE_PROCESS_INFO_T;

typedef struct
{
    /**
     * 图像处理单元的上下文
     */
    void *ctx;

    char * (*image_process_version)(void);
    /**
     * 初始化
     * @param ctx 上下文
     * @param fd  文件描述符 如果没有用到就给-1
     * @param src   原图的空间
     * @param srcSize 原图的空间大小
     * @param dstFd  文件描述符 如果没有用到就给-1
     * @param dst    目标的空间
     * @param dstSize 目标的空间大小
     */
    RET_CODE (*image_process_init)(const void *ctx,
                        int srcFd,int srcChannel,void *src,size_t srcSize,
                        uint64_t dstFd,int dstChannel,void *dst,size_t dstSize);
    /**
     *
     * @param info 处理的信息
     */
    RET_CODE (*image_process)(const void *ctx,const IMAGE_PROCESS_INFO_T *info);
    /**
     * 反初始化
     * @param ctx 上下文
     */
    RET_CODE (*image_process_deInit)(const void *ctx);
}MPP_IMAGE_PROCESS_T;


/**********************************************************/
/********************视频解码接口**************************/
/**********************************************************/



/*
 *
 *fd:帧的FD
 *fame:一帧的数据
 *length:长度
 * */
typedef void  (* decode_frame_callback)(void *ctx,void *usr_arg,int fd,uint8_t *fame,uint32_t length);
typedef struct 
{
    /** 注意此参数不能在外部修改
     * @brief 解码器的空间 
     * addr 待解码的头指针
     * length 待解码的长度
     * extend  解码器的内部扩展(解码器内部使用)
     */
    uint8_t *addr;
    uint32_t length;
    void *extend;
}MPP_DECODE_BUF;

typedef struct 
{
    /*
     *解码器上下文
     *注意：这个值不允许用户在外部重新赋值
     */
    void *ctx;
    /*初始化
     *type:输入码流的类型
     *decFormat:输出编码的格式，YUV420，NV12等类型，默认使用NV12
     *height:码流的高度
     *width:码流的宽度
     *dstHeight:解码后YUV的高度
     *dstWidth:解码后YUV的宽度
     *isDisplay:是否显示
     *
    */
    RET_CODE  (*mpp_dec_init)(void *ctx,const CODE_TYPE type ,  const FRAME_TYPE decFormat,
                                const uint32_t height,const uint32_t width,
                                const uint32_t dstHeight,const uint32_t dstWidth, 
                                const bool isDisplay);
    /**
     * @brief 创建解码器的空间
     * 
     */
    MPP_DECODE_BUF * (*mpp_dec_create_buffer)(void *ctx); 


    /**
     * @brief  销毁解码器的空间
     * 
     */
    void  (*mpp_dec_detroy_buffer)(void *ctx,MPP_DECODE_BUF **buf); 


    
    /**
     * @brief 复制数据到解码器缓存
     * 
     */

    void  (*mpp_dec_copy_buffer)(void *ctx,MPP_DECODE_BUF *decode_buf,void *h26x_buf,int32_t length); 
    /**
     * @brief 设置数据的长度
     * 
     */
     void  (*mpp_dec_set_buffer_length)(void *ctx,MPP_DECODE_BUF *decode_buf,int32_t length); 
    /*解码
     *push:输入码流
     *length:长度
     *isEnd:是否最后一帧
    */
    RET_CODE  (*mpp_dec_push)(void *ctx,MPP_DECODE_BUF *decode_buf,bool isEnd);
    /*
     *注册解码完成回调函数
     * */
    void (*mpp_dec_regist_done_callback)(void *ctx, void *usr_arg,  decode_frame_callback callback);

    /*吐帧
     *fd:拿到硬件硬件编码的fd
     *output:拿到解码完成的帧数据
     *length:拿到解码器完成帧的长度
     *目前暂时没有去实现
     */
    RET_CODE  (*mpp_dec_dump_Frame)(void *ctx,const int fd,uint8_t **output,size_t *length);
    /*
     *反初始化
    */
    RET_CODE  (*mpp_dec_deinit)(void *ctx);
}MPP_ITC_DEC_FUNTION;//,mpp_itc_dec_funtion





/**********************************************************/
/**********************************************************/
/**********************************************************/


/**********************************************************/
/******************视频编码接口****************************/
/**********************************************************/
typedef enum
{
    ENC_ROTATION_0,
    ENC_ROTATION_90,
    ENC_ROTATION_180,
    ENC_ROTATION_270,
}ENC_ROTATION;
typedef enum
{
    ENC_MIRRORING_DISABLE,//--不用镜像
    ENC_MIRRORING_HOR,//--水平镜像
    ENC_MIRRORING_VER,//--垂直镜像
}ENC_MIRRORING;
typedef struct
{
    ENCODE_RC_MODE mode;//--编码模式VBR,CBR等
    uint32_t bps_vbr_max;//--VBR下的最高码率
    uint32_t bps_vbr_min;//--VBR下的最低码率
    uint32_t bps_cbr;    //--CBR固定码率
    uint32_t gop;        //--I帧间隔
    uint32_t fps;       //--帧率
    ENC_ROTATION rotation; //--翻转
    ENC_MIRRORING mirroring;//--镜像

}ENC_CONFIG;

/*
 *解码完成回调函数
 * */
typedef void (*mpp_enc_callback)(int fd,uint8_t *data,uint32_t length);
typedef struct
{
    /*
     *编码器上下文
     *注意：这个值不允许用户在外部重新赋值
     * */
    void *cxt;
    /*
     *编码初始化
     *cxt:上下文
     *height:输入的视频高度
     *width:输入视频的宽度
     *type:编码类型
     *frame:输入帧的数据格式 YUV420SP 等
     *conig:编码参数配置
    */
    RET_CODE (*mpp_enc_init)(void *cxt,
            const uint32_t height,const uint32_t width,
            const CODE_TYPE type,const FRAME_TYPE frame,
            ENC_CONFIG *config);
    /*
     *请求I帧
     * */
    RET_CODE (*mpp_enc_request_I_frame)(void *cxt);
    /*
     *注册编码回调函数
     * */
    void (*mpp_enc_done_register_callback)(mpp_enc_callback callback);
    /*
     *喂帧
     * */
    RET_CODE (*mpp_enc_inpush)(void *cxt,uint8_t *date,uint32_t length);
    /*
     *反初始化
     * */
    RET_CODE (*mpp_enc_deinit)(void *cxt);

}MPP_ITC_ENC_FUNTION;//,mpp_itc_enc_funtion;

/**********************************************************/
/**********************************************************/
/**********************************************************/


/**********************************************************/
/******************显示接口*******************************/
/**********************************************************/
typedef void* MPP_SURFACE;


typedef struct 
{
    uint32_t s32X;
    uint32_t s32Y;
    uint32_t u32Width;
    uint32_t u32Height;
}MPP_SURFACE_RECT_S;
typedef struct
{
    //--注意：以下参数不需要用户配置   注意：画布的宽度和高度实际值还是和屏幕的宽度高度一致的，如果设置画布的宽度和高度就等于当前画布缩放而已，不影响数据的宽高
    /**************注意：以下参数不需要用户配置***********************/
    MPP_SURFACE surface;
    uint32_t position_x;        //--当前画布在窗口的x点
    uint32_t position_y;        //--当前画布在窗口的y点
    uint32_t width;               //--当前画布的宽度  
    uint32_t height;              //--当前画布的高度 
    uint32_t format;              //--当前画布的格式
    int fd;                              //--要往画布上画图数据的文件描述符(海思平台传的是模块ID号    例如VPSS的ID)
    int subfd;                        //--兼容海思平台使用(海思平台传的是模块ID号     例如VPSS的子通道ID)

    uint32_t count_rect;                   //--宫格画面数量
    MPP_SURFACE_RECT_S  *rect;    //--宫格画面信息 标记了每个画面的坐标七点与宽度和高度
    

    /***********************************************************************/

    /********************以下参数为mmap之后的数据，用户可以操作***************************/
    uint32_t count_framebuffer; //--画布数量
    void *framebuffer[32];          //--画布上的数据
}MPP_SURFACE_ATTR;


typedef struct
{
    //--注意：以下参数不需要用户配置
    /**************注意：以下参数不需要用户配置***********************/
    uint32_t width;               //--当前屏幕的宽度  
    uint32_t height;              //--当前屏幕的高度 
    uint32_t vrefresh;           //--当前屏幕的刷新率
}MPP_SCREEN_ATTR;




typedef struct
{
    /*
     *显示上下文
     *注意：这个值不允许用户在外部重新赋值
     * */
    void *cxt;

    /**
     * @brief mpp_display_init 初始化显示设备
     * 
     */
    RET_CODE (*mpp_display_init)(void *cxt,uint32_t width ,uint32_t height,uint32_t vrefresh);



    MPP_SCREEN_ATTR *(*mpp_display_get_screen_attr)(void *cxt);
    /**
     * @brief  mpp_create_surface 创建一个表面
     * 目前只能创建一个图层
     */
    MPP_SURFACE_ATTR *(*mpp_create_surface)(void *cxt,FRAME_TYPE format,uint32_t position_x,uint32_t position_y,uint32_t width,uint32_t height);
    /**
     * @brief 在画布上话图
     * position_x 矩阵的起始点x坐标
     * position_y 矩阵的起始点y坐标
     * width    矩阵的宽度
     * height    矩阵的高度
     */
    RET_CODE (*mpp_surface_draw)(void *cxt,MPP_SURFACE_ATTR *surface,
                                    uint32_t position_x ,uint32_t position_y,
                                    uint32_t width ,uint32_t height);

    /**
     * @brief 创建宫格画面
     *  cout_rects 数量
     *  rect      宫格画面信息
     */
    RET_CODE (*mpp_surface_create_rects)(void *cxt,MPP_SURFACE_ATTR *surface,
                                    uint32_t count_rects,MPP_SURFACE_RECT_S  *rect);



                                    

    /**
     * @brief 往宫格中写入数据
     * index 第N号宫格
     * data   数据
     * 
     */
    RET_CODE (*mpp_surface_rect_draw)(void *cxt,MPP_SURFACE_ATTR *surface,
                                    uint32_t index,void *data,uint32_t width ,uint32_t height);

    /**
     * @brief 销毁宫格画面
     * 
     */

    RET_CODE (*mpp_surface_destroy_rects)(void *cxt,MPP_SURFACE_ATTR *surface);


    /**
     * @brief 
     * 
     */
    RET_CODE (*mpp_destroy_surface)(void *cxt,MPP_SURFACE_ATTR *surface);
    /**
     * @brief 
     * 
     */
    RET_CODE (*mpp_display_deinit)(void *cxt);

}MPP_ITC_DISPLAY_FUNTION_T;

#ifdef __cplusplus
}
#endif

#endif
